﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Linq;
using System.Net;
using Newtonsoft.Json;
using System.Collections.Concurrent;

namespace Tsual.DataPipeline.Http
{
    public abstract class AbstractHttpPipe<T, TMeta> : IDataPipeDescription<T, TMeta>
    {
        protected IHttpClientFactory httpClientFactory;

        public AbstractHttpPipe(IHttpClientFactory httpClientFactory)
        {
            this.httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
        }

        public abstract bool CanRead(TMeta meta);

        public abstract bool CanWrite(T data, TMeta meta);

        public abstract Task<DataPipeReadResult<T>> Read(TMeta meta);

        public abstract Task<DataPipeWriteResult> Write(T data, TMeta meta);
    }

    public class ReadonlyHttpPipe<T, TMeta> : AbstractHttpPipe<T, TMeta>
        where TMeta : IConvertible<HttpRequestMessage>, IConvertible<Func<HttpResponseMessage, Task<T>>>
    {
        public ReadonlyHttpPipe(IHttpClientFactory httpClientFactory) : base(httpClientFactory)
        {
        }

        public override bool CanRead(TMeta meta) => true;

        public override bool CanWrite(T data, TMeta meta) => false;

        public override async Task<DataPipeReadResult<T>> Read(TMeta meta)
        {
            var request = ((IConvertible<HttpRequestMessage>)meta).Convert();
            if (request == null) return DataPipeReadResult<T>.Notfound();
            var response = await httpClientFactory.CreateClient().SendAsync(request);
            if (response.IsSuccessStatusCode)
            {
                var func = ((IConvertible<Func<HttpResponseMessage, Task<T>>>)meta).Convert();
                return DataPipeReadResult<T>.Success(await func(response));
            }
            else if (response.StatusCode == HttpStatusCode.NotFound)
                return DataPipeReadResult<T>.Notfound();
            else return DataPipeReadResult<T>.Error();
        }

        public override Task<DataPipeWriteResult> Write(T data, TMeta meta)
        {
            throw new NotImplementedException();
        }
    }

    public class WriteonlyHttpPipe<T, TMeta> : AbstractHttpPipe<T, TMeta>
        where TMeta : IConvertible<HttpRequestMessage, T>
    {
        public WriteonlyHttpPipe(IHttpClientFactory httpClientFactory) : base(httpClientFactory)
        {
        }

        public override bool CanRead(TMeta meta)
        {
            return false;
        }

        public override bool CanWrite(T data, TMeta meta)
        {
            return true;
        }

        public override Task<DataPipeReadResult<T>> Read(TMeta meta)
        {
            throw new NotImplementedException();
        }

        public override async Task<DataPipeWriteResult> Write(T data, TMeta meta)
        {
            var request = ((IConvertible<HttpRequestMessage, T>)meta).Convert(data);
            var response = await httpClientFactory.CreateClient().SendAsync(request);
            if (response.IsSuccessStatusCode)
                return DataPipeWriteResult.Success();
            else return DataPipeWriteResult.Error();
        }
    }
}
